<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="SSm1i" id="SSm1i"><span data-lake-id="u579c4213" id="u579c4213">典型回答</span></h1>
  <p data-lake-id="u63fa5aa7" id="u63fa5aa7"><span data-lake-id="ud1beca36" id="ud1beca36">AOP(Aspect-Oriented Programming)，即</span><span data-lake-id="u2eb86546" id="u2eb86546">面向切面编程</span><span data-lake-id="u48fa49bb" id="u48fa49bb">，用人话说就是把公共的逻辑抽出来，让开发者可以更专注于业务逻辑开发。</span></p>
  <p data-lake-id="ufcb9db70" id="ufcb9db70"><span data-lake-id="ubb7dd943" id="ubb7dd943">​</span><br></p>
  <p data-lake-id="u0c833eb3" id="u0c833eb3"><span data-lake-id="u726f8699" id="u726f8699">和IOC一样，AOP也指的是一种思想。AOP思想是OOP（Object-Oriented Programming）的补充。OOP是面向类和对象的，但是AOP则是面向不同切面的。一个切面可以横跨多个类和对象去操作，极大的丰富了开发者的使用方式，提高了开发效率。</span></p>
  <p data-lake-id="uecef7e15" id="uecef7e15"><span data-lake-id="ucbe1250e" id="ucbe1250e">​</span><br></p>
  <p data-lake-id="u5bae3f39" id="u5bae3f39"><span data-lake-id="ueadf3f9d" id="ueadf3f9d">譬如，一个订单的创建，可能需要以下步骤：</span></p>
  <ol list="ue0212c84">
   <li fid="u79f86847" data-lake-id="u0ef2068b" id="u0ef2068b"><span data-lake-id="u3e6bbce7" id="u3e6bbce7">权限校验</span></li>
   <li fid="u79f86847" data-lake-id="ub0958835" id="ub0958835"><span data-lake-id="u618b42a6" id="u618b42a6">事务管理</span></li>
   <li fid="u79f86847" data-lake-id="uf818dc0d" id="uf818dc0d"><span data-lake-id="ucb7e10a8" id="ucb7e10a8">创建订单</span></li>
   <li fid="u79f86847" data-lake-id="uf1d800ad" id="uf1d800ad"><span data-lake-id="u9593c5db" id="u9593c5db">日志打印</span></li>
  </ol>
  <p data-lake-id="ucd804e4b" id="ucd804e4b"><span data-lake-id="u91426ca7" id="u91426ca7">如果使用AOP思想，我们就可以把这四步当成四个“切面”，让业务人员专注开发第三个切面，其他三个切面则是基础的通用逻辑，统一交给AOP封装和管理。</span></p>
  <p data-lake-id="udae5c9f9" id="udae5c9f9"><span data-lake-id="uc48a8265" id="uc48a8265">​</span><br></p>
  <p data-lake-id="u09c934cc" id="u09c934cc"><span data-lake-id="u6afad6de" id="u6afad6de">Spring AOP有如下概念（列举下，不用刻意记）：</span></p>
  <table data-lake-id="gCi8d" id="gCi8d" margin="true" class="lake-table" style="width: 778px">
   <colgroup>
    <col width="102">
    <col width="102">
    <col width="574">
   </colgroup>
   <tbody>
    <tr data-lake-id="u9cc88c9f" id="u9cc88c9f" style="height: 33px">
     <td data-lake-id="u02f15eea" id="u02f15eea">
      <p data-lake-id="ud31e09bb" id="ud31e09bb"><span data-lake-id="u63877a26" id="u63877a26">术语</span></p></td>
     <td data-lake-id="u456c86c6" id="u456c86c6" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="uef8078f5" id="uef8078f5"><span data-lake-id="u74ee6c7a" id="u74ee6c7a">翻译</span></p></td>
     <td data-lake-id="ua93c6d5f" id="ua93c6d5f">
      <p data-lake-id="u9797b66d" id="u9797b66d"><span data-lake-id="ub19f6440" id="ub19f6440">释义</span></p></td>
    </tr>
    <tr data-lake-id="u1086c028" id="u1086c028" style="height: 33px">
     <td data-lake-id="u2256670c" id="u2256670c">
      <p data-lake-id="ue8c1d9d2" id="ue8c1d9d2"><span data-lake-id="ubfa2d044" id="ubfa2d044">Aspect</span></p></td>
     <td data-lake-id="u70df9bab" id="u70df9bab" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u8773f4ea" id="u8773f4ea"><span data-lake-id="u3b40f2ba" id="u3b40f2ba">切面</span></p></td>
     <td data-lake-id="u7a4b5781" id="u7a4b5781">
      <p data-lake-id="ue6509db2" id="ue6509db2"><span data-lake-id="ue5f1c735" id="ue5f1c735">切面由</span><span data-lake-id="u7abd7a17" id="u7abd7a17">切入点</span><span data-lake-id="ud221db97" id="ud221db97">和</span><span data-lake-id="ue78efd14" id="ue78efd14">通知</span><span data-lake-id="u3ce3e9a8" id="u3ce3e9a8">组成，它既包含了横切逻辑的定义，也包括了切入点的定义。</span><span data-lake-id="u436bf609" id="u436bf609">切面是一个横切关注点的模块化，一个切面能够包含同一个类型的不同增强方法，比如说事务处理和日志处理可以理解为两个切面。</span></p></td>
    </tr>
    <tr data-lake-id="ue8f71cc9" id="ue8f71cc9" style="height: 33px">
     <td data-lake-id="u7812daee" id="u7812daee" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="uf4f63a90" id="uf4f63a90"><span data-lake-id="u782381ab" id="u782381ab">PointCut</span></p></td>
     <td data-lake-id="u3736924a" id="u3736924a" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="ue006dca5" id="ue006dca5"><span data-lake-id="u679f3c58" id="u679f3c58">切入点</span></p></td>
     <td data-lake-id="u3e0d4893" id="u3e0d4893" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u57d4902d" id="u57d4902d"><span data-lake-id="uab5387e5" id="uab5387e5">切入点是对</span><span data-lake-id="ubf0701f4" id="ubf0701f4">连接点</span><span data-lake-id="ue92c4c12" id="ue92c4c12">进行拦截的</span><span data-lake-id="u066d2e6e" id="u066d2e6e">条件定义</span><span data-lake-id="uf1ef98b1" id="uf1ef98b1">，</span><span data-lake-id="u9d5b539d" id="u9d5b539d">决定</span><span data-lake-id="ub486ff6b" id="ub486ff6b">通知</span><span data-lake-id="u7c17b9e7" id="u7c17b9e7">应该作用于截哪些方法。（充当where角色，即在哪里做）</span></p></td>
    </tr>
    <tr data-lake-id="u8408a1cb" id="u8408a1cb" style="height: 33px">
     <td data-lake-id="u3763d096" id="u3763d096" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u747d1ea6" id="u747d1ea6"><span data-lake-id="u62065628" id="u62065628">Advice</span></p></td>
     <td data-lake-id="ud63022dd" id="ud63022dd" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="ua0563172" id="ua0563172"><span data-lake-id="u67e67e9a" id="u67e67e9a">通知</span></p></td>
     <td data-lake-id="u9ec59c41" id="u9ec59c41" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="ue0d97d08" id="ue0d97d08"><span data-lake-id="u541acf82" id="u541acf82">通知定义了通过</span><span data-lake-id="u86e3cf8b" id="u86e3cf8b">切入点</span><span data-lake-id="u12ed58af" id="u12ed58af">拦截后，应该在</span><span data-lake-id="ub7b87b70" id="ub7b87b70">连接点</span><span data-lake-id="u7c97768a" id="u7c97768a">做什么，是切面的具体行为。（充当what角色，即做什么）</span></p></td>
    </tr>
    <tr data-lake-id="u356bcd37" id="u356bcd37" style="height: 33px">
     <td data-lake-id="udf4c437d" id="udf4c437d" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u356b704d" id="u356b704d"><span data-lake-id="u4508a8cf" id="u4508a8cf">Target</span></p></td>
     <td data-lake-id="u7f194a41" id="u7f194a41" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="uce99a587" id="uce99a587"><span data-lake-id="u09834ab8" id="u09834ab8">目标对象</span></p></td>
     <td data-lake-id="u60b6361d" id="u60b6361d" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u0c36146d" id="u0c36146d"><span data-lake-id="u6f2f9f9f" id="u6f2f9f9f">目标对象指将</span><span data-lake-id="u9fc6e7c6" id="u9fc6e7c6">要被增强的对象</span><span data-lake-id="ua7789a55" id="ua7789a55">，即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。</span></p></td>
    </tr>
    <tr data-lake-id="u8cbdf88f" id="u8cbdf88f" style="height: 33px">
     <td data-lake-id="u05aff97d" id="u05aff97d" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="ub2aa4394" id="ub2aa4394"><span data-lake-id="ued7bee40" id="ued7bee40">JoinPoint</span></p></td>
     <td data-lake-id="u6ac6998b" id="u6ac6998b" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="uffbae51e" id="uffbae51e"><span data-lake-id="ue49a1bd9" id="ue49a1bd9">连接点</span></p></td>
     <td data-lake-id="udc2a06ce" id="udc2a06ce" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u7858d22e" id="u7858d22e"><span data-lake-id="ucc4d50db" id="ucc4d50db">连接点是程序在运行时的</span><span data-lake-id="u2fed79a0" id="u2fed79a0">执行点</span><span data-lake-id="ub713156a" id="ub713156a">，这个点可以是正在执行的方法，或者是正在抛出的异常。</span><span data-lake-id="uf4b267e3" id="uf4b267e3">因为Spring只支持方法类型的连接点，所以在Spring中连接点就是</span><span data-lake-id="uae8771e9" id="uae8771e9">运行时刻</span><span data-lake-id="u2c8f09f0" id="u2c8f09f0">被拦截到的方法。</span><span data-lake-id="u1315daee" id="u1315daee">连接点由两个信息确定：</span></p>
      <ul list="ucef130bc">
       <li fid="uf156e0d0" data-lake-id="u541de5d3" id="u541de5d3"><span data-lake-id="uc52bf1ae" id="uc52bf1ae">方法(表示程序执行点，即在哪个目标方法)</span></li>
       <li fid="uf156e0d0" data-lake-id="u5545a4b5" id="u5545a4b5"><span data-lake-id="u87e63159" id="u87e63159">相对点(表示方位，即目标方法的什么位置，比如调用前，后等)</span></li>
      </ul></td>
    </tr>
    <tr data-lake-id="uf751c651" id="uf751c651" style="height: 33px">
     <td data-lake-id="ucf70283a" id="ucf70283a" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="uea7848e1" id="uea7848e1"><span data-lake-id="u4038092f" id="u4038092f">Weaving</span></p></td>
     <td data-lake-id="ufaef24f3" id="ufaef24f3" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u7b17f7fe" id="u7b17f7fe"><span data-lake-id="ua547d773" id="ua547d773">织入</span></p></td>
     <td data-lake-id="uccc96586" id="uccc96586" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="ufe903a6f" id="ufe903a6f"><span data-lake-id="u20017762" id="u20017762">织入是将</span><span data-lake-id="ua9eb1000" id="ua9eb1000">切面</span><span data-lake-id="u5626903b" id="u5626903b">和</span><span data-lake-id="u57cbad58" id="u57cbad58">业务逻辑</span><span data-lake-id="udafbd607" id="udafbd607">对象连接起来, 并创建通知</span><span data-lake-id="ud85fc4eb" id="ud85fc4eb">代理</span><span data-lake-id="u1cc8c301" id="u1cc8c301">的过程。织入可以在</span><span data-lake-id="u3c3ea2d0" id="u3c3ea2d0">编译</span><span data-lake-id="ueac9f360" id="ueac9f360">时，类</span><span data-lake-id="ua5df7de6" id="ua5df7de6">加载</span><span data-lake-id="u1449507c" id="u1449507c">时和</span><span data-lake-id="uf27e4543" id="uf27e4543">运行</span><span data-lake-id="uc0f87273" id="uc0f87273">时完成。在编译时进行织入就是</span><span data-lake-id="u433b25a7" id="u433b25a7">静态代理</span><span data-lake-id="ubced55e9" id="ubced55e9">，而在运行时进行织入则是</span><span data-lake-id="u8b1dd1d5" id="u8b1dd1d5">动态代理</span><span data-lake-id="u3df6fd27" id="u3df6fd27">。</span></p></td>
    </tr>
   </tbody>
  </table>
  <p data-lake-id="ue8de0c46" id="ue8de0c46"><span data-lake-id="u6e34a322" id="u6e34a322">对于通知类型来说：</span></p>
  <table data-lake-id="VAfyR" id="VAfyR" margin="true" class="lake-table" style="width: 730px">
   <colgroup>
    <col width="178">
    <col width="552">
   </colgroup>
   <tbody>
    <tr data-lake-id="u460c6ea5" id="u460c6ea5" style="height: 33px">
     <td data-lake-id="u8b19b220" id="u8b19b220">
      <p data-lake-id="u6ef88d53" id="u6ef88d53"><span data-lake-id="u4044754e" id="u4044754e">Before Advice</span></p></td>
     <td data-lake-id="u98a24ec2" id="u98a24ec2">
      <p data-lake-id="u5ff7ff78" id="u5ff7ff78"><span data-lake-id="u9d5d1ec2" id="u9d5d1ec2">连接点</span><span data-lake-id="u47066400" id="u47066400">执行前</span><span data-lake-id="uf2b94e96" id="uf2b94e96">执行的逻辑</span></p></td>
    </tr>
    <tr data-lake-id="u96462b75" id="u96462b75" style="height: 33px">
     <td data-lake-id="ue217d72b" id="ue217d72b">
      <p data-lake-id="u6fa16e47" id="u6fa16e47"><span data-lake-id="uce1f9391" id="uce1f9391">After returning advice</span></p></td>
     <td data-lake-id="uabe0cb76" id="uabe0cb76">
      <p data-lake-id="u658a072b" id="u658a072b"><span data-lake-id="ud5c4528c" id="ud5c4528c">连接点</span><span data-lake-id="u96c594be" id="u96c594be">正常执行（未抛出异常）后</span><span data-lake-id="ubfae8a74" id="ubfae8a74">执行的逻辑</span></p></td>
    </tr>
    <tr data-lake-id="u4aaa87a0" id="u4aaa87a0" style="height: 33px">
     <td data-lake-id="u49179490" id="u49179490" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u7e871f65" id="u7e871f65"><span data-lake-id="uc97569f6" id="uc97569f6">After throwing advice</span></p></td>
     <td data-lake-id="uc64bb015" id="uc64bb015" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="ua550f6ff" id="ua550f6ff"><span data-lake-id="u18a6a651" id="u18a6a651">连接点</span><span data-lake-id="ubacbb2c2" id="ubacbb2c2">抛出异常后</span><span data-lake-id="u2c1789ed" id="u2c1789ed">执行的逻辑</span></p></td>
    </tr>
    <tr data-lake-id="ua1f509a9" id="ua1f509a9" style="height: 33px">
     <td data-lake-id="u59fe2c2e" id="u59fe2c2e" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u1a6c3a28" id="u1a6c3a28"><span data-lake-id="u2a6166cd" id="u2a6166cd">After finally advice</span></p></td>
     <td data-lake-id="u5ba8f2ed" id="u5ba8f2ed" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="ua15e2b96" id="ua15e2b96"><span data-lake-id="u39d080d1" id="u39d080d1">无论连接点是正常执行还是抛出异常，在连接点执行完毕后执行的逻辑</span></p></td>
    </tr>
    <tr data-lake-id="u62942cb4" id="u62942cb4" style="height: 33px">
     <td data-lake-id="ud36d6855" id="ud36d6855" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="u0b66c770" id="u0b66c770"><span data-lake-id="u23b54cdd" id="u23b54cdd">Around advice</span></p></td>
     <td data-lake-id="u42807519" id="u42807519" style="background-color: #FFFFFF; vertical-align: top">
      <p data-lake-id="ue43e0a2d" id="ue43e0a2d"><span data-lake-id="u18c774da" id="u18c774da">该通知可以非常灵活的</span><span data-lake-id="u41edfd20" id="u41edfd20">在方法调用前后</span><span data-lake-id="ud12e347b" id="ud12e347b">执行特定的逻辑</span></p></td>
    </tr>
   </tbody>
  </table>
  <h1 data-lake-id="GdpVQ" id="GdpVQ"><span data-lake-id="ub5b091ee" id="ub5b091ee">扩展知识</span></h1>
  <p data-lake-id="ua050ea91" id="ua050ea91"><br></p>
  <h2 data-lake-id="sW21i" id="sW21i"><span data-lake-id="ufc9b83e9" id="ufc9b83e9">AOP是如何实现的？</span></h2>
  <p data-lake-id="ude83e9da" id="ude83e9da"><br></p>
  <p data-lake-id="u87f961b0" id="u87f961b0"><span data-lake-id="u1f7aff85" id="u1f7aff85">​</span><br></p>
  <p data-lake-id="u8bb54a4c" id="u8bb54a4c"><span data-lake-id="u726d0e11" id="u726d0e11">从Bean的初始化流程中来讲，Spring的AOP会在bean实例的实例化已完成，进行初始化后置处理时创建代理对象，即下面代码中的applyBeanPostProcessorsAfterInitialization部分。</span></p>
  <p data-lake-id="u7bcde1c9" id="u7bcde1c9"><span data-lake-id="uaa262618" id="uaa262618">​</span><br></p>
  <pre lang="java"><code>
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {

    //...
    //检查Aware
    invokeAwareMethods(beanName, bean);
    
	//调用BeanPostProcessor的前置处理方法
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    //调用InitializingBean的afterPropertiesSet方法或自定义的初始化方法及自定义init-method方法
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    //调用BeanPostProcessor的后置处理方法
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}
</code></pre>
  <p data-lake-id="uf9a79c58" id="uf9a79c58"><span data-lake-id="u0bc5f48f" id="u0bc5f48f">​</span><br></p>
  <p data-lake-id="ub1f860cc" id="ub1f860cc"><span data-lake-id="uc62899a4" id="uc62899a4">​</span><br></p>
  <p data-lake-id="uf99f7bb4" id="uf99f7bb4"><span data-lake-id="u260d8f62" id="u260d8f62">applyBeanPostProcessorsAfterInitialization中会遍历所有BeanPostProcessor，然后</span></p>
  <p data-lake-id="u1d9bf8ef" id="u1d9bf8ef"><span data-lake-id="ud23d9238" id="ud23d9238">调用其postProcessAfterInitialization方法，而AOP代理对象的创建就是在AbstractAutoProxyCreator这个类的postProcessAfterInitialization&#x0;中：</span></p>
  <p data-lake-id="u59b58bdb" id="u59b58bdb"><span data-lake-id="u0d6d49cd" id="u0d6d49cd">​</span><br></p>
  <pre lang="java"><code>
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

</code></pre>
  <p data-lake-id="uab598c14" id="uab598c14"><br></p>
  <p data-lake-id="u3912b823" id="u3912b823"><span data-lake-id="ucf0ce960" id="ucf0ce960">这里面最重要的就是wrapIfNecessary方法了：</span></p>
  <p data-lake-id="u1badfde5" id="u1badfde5"><span data-lake-id="u7a58784a" id="u7a58784a">​</span><br></p>
  <pre lang="java"><code>
/**
 * 如果需要，对bean进行包装。
 *
 * @param bean 要包装的目标对象
 * @param beanName bean的名称
 * @param cacheKey 缓存键
 * @return 包装后的对象，可能是原始对象或代理对象
 */
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 如果beanName不为null且在目标源bean集合中，则直接返回原始对象
    if (beanName != null &amp;&amp; this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }

    // 如果缓存键对应的值为Boolean.FALSE，则直接返回原始对象
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }

    // 如果bean的类型为基础设施类，或者应跳过该类型的代理，则将缓存键对应的值设置为Boolean.FALSE并返回原始对象
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // 如果存在advice，为bean创建代理对象
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        // 将缓存键对应的值设置为Boolean.TRUE
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理对象
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        // 将代理对象的类型与缓存键关联起来
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    // 如果没有advice，将缓存键对应的值设置为Boolean.FALSE并返回原始对象
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

</code></pre>
  <p data-lake-id="u82e9537a" id="u82e9537a"><br></p>
  <p data-lake-id="ue1cf295d" id="ue1cf295d"><span data-lake-id="u8c6e1025" id="u8c6e1025">createProxy的主要作用是根据给定的bean类、bean名称、特定拦截器和目标源，创建代理对象：</span></p>
  <p data-lake-id="u209985b6" id="u209985b6"><span data-lake-id="uf08ce29b" id="uf08ce29b">​</span><br></p>
  <pre lang="java"><code>
/**
 * 根据给定的bean类、bean名称、特定拦截器和目标源，创建代理对象。
 *
 * @param beanClass 要代理的目标对象的类
 * @param beanName bean的名称
 * @param specificInterceptors 特定的拦截器数组
 * @param targetSource 目标源
 * @return 创建的代理对象
 */
protected Object createProxy(
        Class&lt;?&gt; beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

    // 如果beanFactory是ConfigurableListableBeanFactory的实例，将目标类暴露给它
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    // 创建ProxyFactory实例，并从当前代理创建器复制配置
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    // 如果不强制使用CGLIB代理目标类，根据条件决定是否使用CGLIB代理
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            // 根据bean类评估代理接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    // 构建advisor数组
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 将advisors添加到ProxyFactory中
    proxyFactory.addAdvisors(advisors);
    // 设置目标源
    proxyFactory.setTargetSource(targetSource);
    // 定制ProxyFactory
    customizeProxyFactory(proxyFactory);

    // 设置代理是否冻结
    proxyFactory.setFrozen(this.freezeProxy);
    // 如果advisors已经预过滤，则设置ProxyFactory为预过滤状态
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    // 获取代理对象，并使用指定的类加载器
    return proxyFactory.getProxy(getProxyClassLoader());
}

</code></pre>
  <p data-lake-id="ubbfc2d33" id="ubbfc2d33"><span data-lake-id="uba562fa4" id="uba562fa4"></span></p>
  <p data-lake-id="u117f8cd0" id="u117f8cd0"><strong><span data-lake-id="uc013920b" id="uc013920b">Spring AOP 是通过代理模式实现的</span></strong><span data-lake-id="udac52618" id="udac52618">，具体有两种实现方式，一种是基于Java原生的动态代理，一种是基于cglib的动态代理。对应到代码中就是，这里面的Proxy有两种实现，分别是CglibAopProxy和JdkDynamicAopProxy。</span></p>
  <p data-lake-id="uee3e2d09" id="uee3e2d09"><span data-lake-id="ud47d5743" id="ud47d5743">​</span><br></p>
  <blockquote data-lake-id="uf01de38c" id="uf01de38c">
   <p data-lake-id="ufc9ed2ec" id="ufc9ed2ec"><strong><span data-lake-id="u3e7a482f" id="u3e7a482f">Spring AOP默认使用标准的JDK动态代理进行AOP代理</span></strong><span data-lake-id="u5d26c7a0" id="u5d26c7a0">。这使得任何接口可以被代理。但是JDK动态代理有一个缺点，就是它不能代理没有接口的类。</span></p>
   <p data-lake-id="uf2efeff7" id="uf2efeff7"><span data-lake-id="u8aa4b7bd" id="u8aa4b7bd">​</span><br></p>
   <p data-lake-id="u87a39410" id="u87a39410"><span data-lake-id="u59271408" id="u59271408">所以Spring AOP就使用CGLIB代理没有接口的类。</span></p>
  </blockquote>
  <p data-lake-id="u8797d5c5" id="u8797d5c5"><br></p>
  <p data-lake-id="uf19dbe0c" id="uf19dbe0c"><img src="https://cdn.nlark.com/yuque/0/2023/png/719664/1673766092954-e6308cd9-ce8d-4854-9b97-1c785721bff4.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_21%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u5f76407a" id="u5f76407a"><span data-lake-id="ua98daac2" id="ua98daac2">​</span><br></p>
  <p data-lake-id="u980eadd6" id="u980eadd6"><span data-lake-id="u908d13fd" id="u908d13fd">当然代理这种设计模式也有动态代理和静态代理之分，可以参考这篇文章：</span></p>
  <p data-lake-id="ubdc15cc7" id="ubdc15cc7"><span data-lake-id="u09771dd3" id="u09771dd3">​</span><br></p>
  <h2 data-lake-id="hJP8c" id="hJP8c"><span data-lake-id="u5388b1b2" id="u5388b1b2">使用AOP可以实现哪些功能？</span></h2>
 </body>
</html>